package com.online.questionnaire.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.online.questionnaire.common.ErrorCode;
import com.online.questionnaire.controller.FileController;
import com.online.questionnaire.exception.BusinessException;
import com.online.questionnaire.exception.ThrowUtils;
import com.online.questionnaire.mapper.AnswerMapper;
import com.online.questionnaire.mapper.SurveySubmitMapper;
import com.online.questionnaire.model.*;
import com.online.questionnaire.model.dto.*;
import com.online.questionnaire.model.vo.UserSurveyStatistics;
import com.online.questionnaire.service.QuestionsService;
import com.online.questionnaire.service.SurveySubmitService;
import com.online.questionnaire.service.SurveysService;
import com.online.questionnaire.mapper.SurveysMapper;
import com.online.questionnaire.service.UserService;
import com.online.questionnaire.utils.CommonUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.online.questionnaire.constant.UserConstant.ADMIN_ROLE;

/**
* @author 27701
* @description 针对表【surveys(问卷表)】的数据库操作Service实现
* @createDate 2025-01-09 16:00:04
*/
@Slf4j
@Service
public class SurveysServiceImpl extends ServiceImpl<SurveysMapper, Surveys>
    implements SurveysService {

    @Resource
    SurveysMapper surveysMapper;

    @Resource
    QuestionsService questionsService;

    @Resource
    private SurveySubmitMapper surveySubmitMapper;
    @Resource
    @Lazy
    private SurveySubmitService surveySubmitService;
    @Resource
    private AnswerMapper answerMapper;
    @Resource
    private UserService userService;

    @Override
    public SurveysDTO getDTOById(Long id) {
        Surveys byId = this.getById(id);
        if (byId == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"题目不存在");
        }
        SurveysDTO surveysDTO = new SurveysDTO();
        BeanUtils.copyProperties(byId,surveysDTO);
        QueryWrapper<Questions> wrapper = new QueryWrapper<>();
        wrapper.select("id");
        wrapper.eq("surveyId",id);
        List<Questions> list = questionsService.list(wrapper);
        List<QuestionsDTO> questionsDTOList = new ArrayList<>();
        for (Questions questions : list) {
            QuestionsDTO questionsDTO = questionsService.getDTOById(questions.getId());
            questionsDTOList.add(questionsDTO);
        }
        //题目按照 orders排序
        questionsDTOList.sort(Comparator.comparing(Questions::getOrders));
        surveysDTO.setQuestions(questionsDTOList);
        Long submitNum = surveySubmitService.getSubmitNum(surveysDTO.getId());
        surveysDTO.setSubmitNum(submitNum);

        return surveysDTO;

    }

    @Override
    @Transactional
    public SurveysDTO updateSurveys(SurveysDTO surveys, Long userId) {
        //检查题目 是否已经有回答数据 有回答数据的禁止修改
        QueryWrapper<SurveySubmit> submitQueryWrapper = new QueryWrapper<>();
        submitQueryWrapper.eq("surveyId",surveys.getId());
        if (surveySubmitMapper.selectCount(submitQueryWrapper) > 0){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"该问卷已有回答数据，禁止修改。请复制问卷后修改");
        }
        surveys.setCreateuserid(userId);
        boolean save = this.saveOrUpdate(surveys);
        if (!save){
            throw new RuntimeException("问卷保存失败");
        }
        //保存成功后的问卷id
        Long surveysId = surveys.getId();
        //清空已有试卷
        QueryWrapper<Questions> delWrapper = new QueryWrapper<>();
        delWrapper.eq("surveyId",surveysId);
        questionsService.remove(delWrapper);

        for (QuestionsDTO question : surveys.getQuestions()) {
            questionsService.saveQuestions(question,surveysId, userId);
        }
        return this.getDTOById(surveysId);
    }

    @Override
    @Transactional
    public SurveysDTO addSurvey(SurveysDTO surveys, Long userId) {
        surveys.setCreateuserid(userId);
        surveys.setId(null);
        boolean save = this.save(surveys);
        if (!save){
            throw new RuntimeException("问卷保存失败");
        }
        //保存成功后的问卷id
        Long surveysId = surveys.getId();

        for (QuestionsDTO question : surveys.getQuestions()) {
            question.setId(null);
            questionsService.addQuestions(question,surveysId, userId);
        }
        return this.getDTOById(surveysId);

    }

    @Override
    @Transactional
    public SurveysDTO addTemplate(SurveysDTO surveys, Long userId) {
        surveys.setIsTemplate(1);
        surveys.setCreateuserid(userId);
        surveys.setId(null);
        boolean save = this.save(surveys);
        if (!save){
            throw new RuntimeException("模板保存失败");
        }
        //保存成功后的问卷id
        Long surveysId = surveys.getId();

        for (QuestionsDTO question : surveys.getQuestions()) {
            question.setId(null);
            questionsService.addQuestions(question,surveysId, userId);
        }
        return this.getDTOById(surveysId);


    }

    @Transactional
    @Override
    public SurveysDTO updateTemplate(SurveysDTO surveys, Long userId) {

        surveys.setCreateuserid(userId);
        surveys.setIsTemplate(1);
        boolean save = this.saveOrUpdate(surveys);
        if (!save){
            throw new RuntimeException("模板保存失败");
        }
        //保存成功后的问卷id
        Long surveysId = surveys.getId();

        //清空已有试卷
        QueryWrapper<Questions> delWrapper = new QueryWrapper<>();
        delWrapper.eq("surveyId",surveysId);
        questionsService.remove(delWrapper);

        for (QuestionsDTO question : surveys.getQuestions()) {
            questionsService.saveQuestions(question,surveysId, userId);
        }
        return this.getDTOById(surveysId);
    }

    @Override
    public SurveyStatisticsDTO getSurveyStatistics(Long surveyId, Long userId) {
        //查看问卷是否存在
        SurveysDTO surveysDTO = this.getDTOById(surveyId);
        if (surveysDTO == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"问卷不存在");
        }
        if (surveysDTO.getIsTemplate() == 1){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"模板问卷无法统计");
        }
        SurveyStatisticsDTO surveyStatisticsDTO = new SurveyStatisticsDTO();
        surveyStatisticsDTO.setSurveyId(surveyId);
        surveyStatisticsDTO.setTitle(surveysDTO.getTitle());
        surveyStatisticsDTO.setUser(userService.getById(userId));
        surveyStatisticsDTO.setItems(new ArrayList<>());

        //开始统计
        List<QuestionsDTO> questionsDTOList = surveysDTO.getQuestions();
        for (QuestionsDTO questionsDTO : questionsDTOList){
            QuestionStatisticsDTO questionStatisticsDTO = new QuestionStatisticsDTO();
            questionStatisticsDTO.setSurveyId(surveyId);
            questionStatisticsDTO.setOrders(questionsDTO.getOrders());
            questionStatisticsDTO.setQuestionId(questionsDTO.getId());
            questionStatisticsDTO.setType(questionsDTO.getType());
            questionStatisticsDTO.setContent(questionsDTO.getContent());
            //统计数量
            //单选、多选
            if (questionsDTO.getType() == 0 || questionsDTO.getType() == 1){
                List<StatisticsItem> optionStatisticsItemList = new ArrayList<>();
                //选项数量 用于计算百分比
//                Integer listSize = questionsDTO.getOptions().size();
                //总和
                long countNum = 0L;
                for (Options option : questionsDTO.getOptions()) {
                    StatisticsItem statisticsItem = new StatisticsItem();
                    statisticsItem.setId(option.getId());
                    statisticsItem.setContent(option.getContent());
                    statisticsItem.setValue(option.getValue());
                    statisticsItem.setPercent(0D);
                    //查询选项的回答数量
                    LambdaQueryWrapper<Answer> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(Answer::getQuestionId,questionsDTO.getId());
                    queryWrapper.eq(Answer::getSurveyId,questionsDTO.getSurveyid());
                    queryWrapper.eq(Answer::getValue,option.getValue());
                    queryWrapper.eq(Answer::getType,questionsDTO.getType());

                    Long count = answerMapper.selectCount(queryWrapper);
                    statisticsItem.setCount(count);
                    if (count > 0){
                        countNum += count;
                    }
                    optionStatisticsItemList.add(statisticsItem);
                }
                //计算百分比
                for (StatisticsItem item : optionStatisticsItemList) {
                    if (item.getCount() > 0){
                        double l = (double) item.getCount() / countNum;
                        //保留三位小数
                        l = Double.parseDouble(new DecimalFormat("#.###").format(l));
                        item.setPercent(l);
                    }
                }
                questionStatisticsDTO.setList(optionStatisticsItemList);

            }

            //填空题 评分与时间选择
            if (questionsDTO.getType() == 2 || questionsDTO.getType() == 3 ||
                questionsDTO.getType() == 4 || questionsDTO.getType() == 5){
                List<StatisticsItem> inputStatisticsItemList = new ArrayList<>();

                //查询该填空题所有回答
                QueryWrapper<Answer> queryWrapper = new QueryWrapper<>();
                queryWrapper.select("value,count(value) as count");
                queryWrapper.eq("questionId",questionsDTO.getId());
                queryWrapper.eq("surveyId",surveysDTO.getId());
                queryWrapper.eq("type",questionsDTO.getType());
                queryWrapper.isNotNull("value");
                queryWrapper.groupBy("value");
                List<Answer> answerList = answerMapper.selectList(queryWrapper);
                //总和
                long countNum = 0L;
                for (Answer answer : answerList) {
                    //查询选项的回答
                    StatisticsItem inputStatisticsItem = new StatisticsItem();
                    inputStatisticsItem.setId(questionsDTO.getId());
                    inputStatisticsItem.setValue(answer.getValue());
                    inputStatisticsItem.setCount(answer.getCount());
                    if (inputStatisticsItem.getCount() > 0){
                        countNum += inputStatisticsItem.getCount();
                    }
                    inputStatisticsItemList.add(inputStatisticsItem);
                }
                // 计算百分比
                for (StatisticsItem item : inputStatisticsItemList) {
                    if (item.getCount() > 0){
                        double l = (double) item.getCount() / countNum;
                        //保留三位小数
                        l = Double.parseDouble(new DecimalFormat("#.###").format(l));
                        item.setPercent(l);
                    }
                }
                questionStatisticsDTO.setList(inputStatisticsItemList);
            }

            surveyStatisticsDTO.getItems().add(questionStatisticsDTO);
        }
        //按照orders排序
        surveyStatisticsDTO.getItems().sort(Comparator.comparing(QuestionStatisticsDTO::getOrders));
        return surveyStatisticsDTO;
    }

    @Override
    public UserSurveyStatistics getUserSurveyStatistics(Long userId) {
        UserSurveyStatistics userSurveyStatistics = new UserSurveyStatistics();
        //获取用户问卷数
        LambdaQueryWrapper<Surveys> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Surveys::getId);
        queryWrapper.eq(Surveys::getIsTemplate, 0);
        queryWrapper.eq(Surveys::getCreateuserid, userId);
        List<Surveys> surveys = surveysMapper.selectList(queryWrapper);
        if (!surveys.isEmpty()){
            userSurveyStatistics.setSurveyNum(surveys.size());
            //获取提交数
            LambdaQueryWrapper<SurveySubmit> submitQueryWrapper = new LambdaQueryWrapper<>();
            submitQueryWrapper.in(SurveySubmit::getSurveyId,
                    surveys.stream().map(Surveys::getId).collect(Collectors.toList()));
            userSurveyStatistics.setSurveySubmitNum(Integer.parseInt(surveySubmitMapper.selectCount(submitQueryWrapper).toString()));
        }else{
            userSurveyStatistics.setSurveyNum(0);
            userSurveyStatistics.setSurveySubmitNum(0);
        }

        //获取模板数
        LambdaQueryWrapper<Surveys> templateQueryWrapper = new LambdaQueryWrapper<>();
        templateQueryWrapper.eq(Surveys::getCreateuserid, userId);
        templateQueryWrapper.eq(Surveys::getIsTemplate, 1);
        List<Surveys> templates = surveysMapper.selectList(templateQueryWrapper);
        if (!templates.isEmpty()){
            userSurveyStatistics.setTemplateNum(templates.size());
            //获取模板申请数  stream 求和
            int sum = templates.stream().mapToInt(Surveys::getTemplateNum).sum();
            userSurveyStatistics.setTemplateApplyNum(sum);
        }else{
            userSurveyStatistics.setTemplateNum(0);
            userSurveyStatistics.setTemplateApplyNum(0);

        }

        return userSurveyStatistics;
    }

    @Override
    public void updateSurveyStatus() {
        //检查问卷 状态与 生效时间不匹配的问卷 修正其状态
        LambdaQueryWrapper<Surveys> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Surveys::getStatus, 1).ne(Surveys::getIsTemplate,1)
                .isNotNull(Surveys::getStarttime)
                .isNotNull(Surveys::getEndtime)
                .and(w -> w.le(Surveys::getStarttime, System.currentTimeMillis())
                        .ge(Surveys::getEndtime, System.currentTimeMillis()));
        List<Surveys> surveysList = surveysMapper.selectList(wrapper);
        for (Surveys surveys : surveysList) {
            log.info("更新问卷{}为已关闭", surveys.getId());
            surveys.setStatus(2);
            surveysMapper.updateById(surveys);
        }
        log.info("更新{}张问卷为已关闭", surveysList.size() );
        wrapper.clear();
        //查询问卷在生效时间内 但状态为未发布的问卷 修正其状态
        wrapper.eq(Surveys::getStatus, 0).ne(Surveys::getIsTemplate,1)
                .isNotNull(Surveys::getStarttime)
                .isNotNull(Surveys::getEndtime)
                .and(w -> w.gt(Surveys::getStarttime, System.currentTimeMillis())
                        .lt(Surveys::getEndtime, System.currentTimeMillis()));
    surveysList = surveysMapper.selectList(wrapper);
        for (Surveys surveys : surveysList) {
            log.info("更新问卷{}为已发布", surveys.getId());
            surveys.setStatus(1);
            surveysMapper.updateById(surveys);
        }
        log.info("更新{}张问卷为已发布", surveysList.size());
    }

    @Override
    public boolean copy(Long id, User user) {
        if (id == null || user == null){
            ThrowUtils.paramsError("id与用户不能为空");
        }
        QueryWrapper<Surveys> wrapper = new QueryWrapper<>();
        wrapper.eq("id",id);

        if (!this.exists(wrapper)){
            ThrowUtils.paramsError("问卷不存在");
        }

        SurveysDTO surveysDTO = this.getDTOById(id);
        surveysDTO.setTitle(surveysDTO.getTitle()+"-复制");
        //只能复制直接创建的问卷 或者 管理员   模板复制非此处
        if (!surveysDTO.getCreateuserid().equals(user.getId()) && !ADMIN_ROLE.equals(user.getUserRole())){
            ThrowUtils.throwIf(true,ErrorCode.NO_AUTH_ERROR);
        }
        surveysDTO.setCreateuserid(user.getId());
        SurveysDTO saveDTO = this.addSurvey(surveysDTO, user.getId());
        return saveDTO != null;
    }

    @Override
    public boolean copyTemplate(Surveys surveys, User user) {
        if (surveys == null || user == null || surveys.getId() == null){
            ThrowUtils.paramsError("id与用户不能为空");
        }
        QueryWrapper<Surveys> wrapper = new QueryWrapper<>();
        wrapper.eq("id",surveys.getId());
        wrapper.eq("isTemplate",1);

        if (!this.exists(wrapper)){
            ThrowUtils.paramsError("模板不存在");
        }

        SurveysDTO surveysDTO = this.getDTOById(surveys.getId());
        //自定义问卷名  为空则使用模板名称
        if (StringUtils.isNotBlank(surveys.getTitle())){
            surveysDTO.setTitle(surveys.getTitle());
        }else{
            surveysDTO.setTitle(surveysDTO.getTitle());
        }
        surveysDTO.setIsTemplate(0);
        surveysDTO.setTemplateNum(0);
        surveysDTO.setCreateuserid(user.getId());
        //创建时间改为现在
        surveysDTO.setCreatetime(new Date());
        //初始状态设为 未发布 起止时间设为空
        surveysDTO.setStatus(0);
        surveysDTO.setStarttime(null);
        surveysDTO.setEndtime(null);

        SurveysDTO saveDTO = this.addSurvey(surveysDTO, user.getId());

        //模板问卷添加 1 使用人数
        QueryWrapper<Surveys> updateWrapper = new QueryWrapper<>();
        updateWrapper.eq("id",surveys.getId());
        updateWrapper.select("id","templateNum");
        Surveys templateSurvey = surveysMapper.selectOne(updateWrapper);
        templateSurvey.setTemplateNum(templateSurvey.getTemplateNum()+1);
        surveysMapper.updateById(templateSurvey);

        return saveDTO != null;
    }

    @Override
    public Map<String,String> exportExcel(Long id,Long userId) {


        //查询问卷
        SurveyStatisticsDTO surveyStatistics = getSurveyStatistics(id, userId);
        int i = 1;
        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        //构造数据
        for (QuestionStatisticsDTO item : surveyStatistics.getItems()){
            Map<String, Object> row = new LinkedHashMap<>();
            row.put("序号", "题目" + i);
            row.put("题目", item.getContent());
            row.put("类型", CommonUtil.getQuestionTypeText(item.getType()));
            row.put("回答内容","");
            int j = 0;
            List<StatisticsItem> list = item.getList();
            if (list == null){
                continue;
            }
            for(StatisticsItem statisticsItem : list){
                //单选或者多选时
                if (item.getType() == 1 || item.getType() == 0){
                    String content = statisticsItem.getContent();
                    //超出一百字裁剪
                    if (content.length() > 100){
                        content = content.substring(0,100) + "...";
                    }
                    Double percent = statisticsItem.getPercent() * 100;
                    //保留两位小数
                    percent = Double.parseDouble(new DecimalFormat("#.##").format(percent));
                    //选项内容
                    row.put(j + "content",content);
                    row.put(content,statisticsItem.getCount() + "/" + percent + "%");
                }else{
                    Double percent = statisticsItem.getPercent() * 100;
                    percent = Double.parseDouble(new DecimalFormat("#.##").format(percent));
                    //输入内容
                    row.put(j + "value",statisticsItem.getValue());
                    //占比
                    row.put(statisticsItem.getValue(),statisticsItem.getCount() + "/" + percent + "%");
                }
                j++;

            }
            i++;
            rows.add(row);
        }

        //写入文件
        String date = DateUtil.format(new Date(), "MM_dd_hh_mm_ss");
        String fileName = surveyStatistics.getTitle() + "_整体统计_" + date + ".xlsx";
        String property = System.getProperty("user.dir");
        String path = property + FileController.savePath + fileName;
        ExcelWriter writer = ExcelUtil.getWriter(path);
        // 合并单元格后的标题行，使用默认标题样式
//        writer.merge(rows.size(), surveyStatistics.getTitle() + "-整体统计");
        writer.write(rows, false);
        writer.close();
        HashMap<String, String> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("path",path);
        objectObjectHashMap.put("name",fileName);
        return objectObjectHashMap;
    }

    @Override
    public Map<String,String> exportExcelByOneAnswer(Long id, Long userId) {
        Surveys byId = this.getById(id);
        ThrowUtils.throwIf(byId == null,ErrorCode.NOT_FOUND_ERROR,"问卷不存在");
        //查询所有的提交记录
        QueryWrapper<SurveySubmit> wrapper = new QueryWrapper<>();
        wrapper.eq("surveyId",id);
        List<SurveySubmit> surveySubmits = surveySubmitService.list(wrapper);
        if (surveySubmits.isEmpty()){
            ThrowUtils.throwIf(true,ErrorCode.NOT_FOUND_ERROR,"问卷下没有提交记录");
        }
        int i = 0;
        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        //查询问卷
        for (SurveySubmit surveySubmit : surveySubmits){
            i++;
            Map<String, Object> row = new LinkedHashMap<>();
            row.put("序号", "第" + i + "份");
            Long submitTime = surveySubmit.getSubmitTime();
            if (submitTime != null){
                //毫秒转成秒
                row.put("耗时", submitTime + "秒");
            }else{
                row.put("耗时", "未记录");
            }
            //转成字符串时间
            row.put("提交时间", DateUtil.format(surveySubmit.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            row.put("浏览器指纹",surveySubmit.getFingerprint());
            row.put("提交用户",surveySubmit.getUserName());

            SurveysDTO surveysDTOAnswer = surveySubmitService.getSurveysDTOAnswer(surveySubmit.getId());

            for (QuestionsDTO questionsDTO : surveysDTOAnswer.getQuestions()) {
                String content = questionsDTO.getContent();
                //超出一百字裁剪
                if (content.length() > 100){
                    content = content.substring(0,100) + "...";
                }
                row.put(content,questionsDTO.getValue());
            }
            rows.add(row);
        }

        //写入文件
        String date = DateUtil.format(new Date(), "MM_dd_hh_mm_ss");
        String fileName = byId.getTitle() + "_答卷统计_" + date + ".xlsx";
        String property = System.getProperty("user.dir");
        String path = property + FileController.savePath + fileName;
        ExcelWriter writer = ExcelUtil.getWriter(path);
        // 合并单元格后的标题行，使用默认标题样式
        writer.merge(rows.size() , byId.getTitle() + "-答卷统计");
        writer.write(rows, true);
        writer.close();
        HashMap<String, String> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("path",path);
        objectObjectHashMap.put("name",fileName);
        return objectObjectHashMap;
    }
}




